#include <iostream.h>
#include <string.h>

#include "stack.h"
#include "queue.h"
#include "datacell.h" 
#include "pgmcell.h"
#include "dictcell.h"
#include "forth.h"

fstack< datacell > data ;
queue< pgmcell > pgm ;
forth interpreter ;

void forth::compile( queue< pgmcell > & pgm )
{
   dictionary.insert( dictionary_cell( pgm.get( 1 ) . svalue , queue< pgmcell >( pgm , 2 ) ) ) ;

   int nelems = pgm.getNumElems() ;

   for ( int i = 0 ; i < nelems ; i++ ) {
      pgmcell pgmc = pgm.extractFirst() ;
   }
}

void forth::interprete( queue< pgmcell > & pgm )
{
   int nelems = pgm.getNumElems() ;

   for ( int i = 0 ; i < nelems ; i++ ) {
      pgmcell pgmc = pgm.extractFirst() ;

      switch ( pgmc.token ) {
         case pgmcell::TK_INT :
         {
            data.push( datacell( pgmc.value ) ) ;
            break ;
         }
         case pgmcell::TK_EMIT :
         {
            cout << (char)data.pop().cell ;
            break ;
         }
         case pgmcell::TK_SPACE :
         {
            cout << " " ;
            break ;
         }
         case pgmcell::TK_SPACES :
         {
            int n = (int)data.pop().cell ;
            for ( int i = 0 ; i < n ; i ++ ) {
               cout << " " ;
            }
            break ;
         }
         case pgmcell::TK_CR :
         {
            cout << endl ;
            break ;
         }
         case pgmcell::TK_VLIST :
         {  
            dictionary_cell dc ;
            int nelems = dictionary.getNumElems() ;
            while ( dictionary.getElem( dc ) ) {
               dc.vlist() ;
            }
            break ;
         }
         case pgmcell::TK_ID :
         {
            dictionary_cell dc ;
            int nelems = dictionary.getNumElems() ;
            for ( int i = 0 ; i < nelems ; i++ ) {
               dc = dictionary.get( i ) ;
               if ( dc.match( pgmc.svalue ) ) {
                  rexecute( dc.pgm ) ;
               }
            }
            break ;
         }
      }
   }
}

bool forth::rexecute( queue< pgmcell > & pgm )
{
   pgmcell pgmc = pgm.getFirst() ;

   if ( pgmc.token == pgmcell::TK_COLON ) {
      compile( pgm ) ;
   }
   else {
      interprete( pgm ) ;
   }
   return true ;   
}

bool forth::execute( queue< pgmcell > & pgm )
{
   pgmcell pgmc = pgm.getFirst() ;

   if ( pgmc.token == pgmcell::TK_COLON ) {
      compile( pgm ) ;
   }
   else {
      interprete( pgm ) ;
   }
   cout << "OK" << endl ;
   return true ;   
}

void forth::save( char * n )
{
 //  dictionary.save( n ) ;
}